/***************************************************************************
*   Copyright (C) 2010 by Peter Hatina                                    *
*   email: phatina (at) gmail.com                                         *
*                                                                         *
*   This program is free software; you can redistribute it and/or modify  *
*   it under the terms of the GNU Lesser General Public License           *
*   version 2.1 as published by the Free Software Foundation              *
*                                                                         *
*   This program is distributed in the hope that it will be useful,       *
*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
*   GNU Lesser General Public License for more details.                   *
*   http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.               *
***************************************************************************/

#include "winregistry.h"

bool WindowsRegistry::keyExists(HKEY rootKey, const std::string & key)
{
    HKEY hKey;
    if (RegOpenKeyExA(rootKey, key.c_str(), 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
    {
        RegCloseKey(hKey);
        return true;
    }

    RegCloseKey(hKey);
    return false;
}

bool WindowsRegistry::entryExists(HKEY rootKey, const std::string & subkey, const std::string & entry)
{
    HKEY hKey;
    if (RegOpenKeyExA(rootKey, subkey.c_str(), 0, KEY_QUERY_VALUE, &hKey)
            == ERROR_SUCCESS)
    {
        DWORD dwDataType = REG_SZ;
        DWORD dwSize = 255;
        if (RegQueryValueExA(hKey, entry.c_str(), 0, &dwDataType,
                             (BYTE *) NULL, &dwSize) == ERROR_SUCCESS)
        {
            RegCloseKey(hKey);
            return true;
        }
    }

    RegCloseKey(hKey);
    return false;
}

std::string WindowsRegistry::getValue(HKEY rootKey, const std::string & subkey, const std::string & entry)
{
    HKEY hKey;
    if (RegOpenKeyExA(rootKey, subkey.c_str(), 0, KEY_QUERY_VALUE, &hKey)
            == ERROR_SUCCESS)
    {
        DWORD dwDataType = REG_SZ;
        DWORD dwSize = 255;
        char *entry_value = new char[dwSize];

        DWORD ret = RegQueryValueExA(hKey, entry.c_str(), 0, &dwDataType,
                                     (BYTE *) entry_value, &dwSize);

        while (ret == ERROR_MORE_DATA)
        {
            dwSize *= 2;
            delete [] entry_value;
            entry_value = new char[dwSize];

            ret = RegQueryValueExA(hKey, entry.c_str(), 0, &dwDataType,
                                   (BYTE *) entry_value, &dwSize);
        }

        if (ret == ERROR_SUCCESS)
        {
            RegCloseKey(hKey);
            std::string ret_value(entry_value);
            delete [] entry_value;
            return ret_value;
        }

        delete [] entry_value;
    }

    RegCloseKey(hKey);
    return "";
}

bool WindowsRegistry::createKey(HKEY rootKey, const std::string & subkey, const std::string & key, const std::string & defaultValue)
{
    HKEY hKey;
    if (RegOpenKeyExA(rootKey, subkey.c_str(), 0, KEY_WRITE, &hKey) == ERROR_SUCCESS)
    {
        if (RegCreateKeyA(hKey, key.c_str(), &hKey) == ERROR_SUCCESS)
        {
            if (!defaultValue.empty())
            {
                if (RegSetValueExA(hKey, "", 0, REG_SZ,
                                   (const BYTE *) defaultValue.c_str(), defaultValue.length()) == ERROR_SUCCESS)
                {
                    ::RegCloseKey(hKey);
                    return true;
                }
                else
                {
                    RegCloseKey(hKey);
                    return false;
                }
            }

            RegCloseKey(hKey);
            return true;
        }
    }

    RegCloseKey(hKey);
    return false;
}

bool WindowsRegistry::deleteKey(HKEY rootKey, const std::string & subkey, const std::string & key)
{
    HKEY hKey;
    if (RegOpenKeyExA(rootKey, subkey.c_str(), 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS)
    {
        if (RegDeleteKeyA(hKey, key.c_str()) == ERROR_SUCCESS)
        {
            RegCloseKey(hKey);
            return true;
        }
    }

    RegCloseKey(hKey);
    return false;
}

bool WindowsRegistry::createEntry(HKEY rootKey, const std::string & subkey, const std::string & entry, const std::string & value)
{
    HKEY hKey;

    RegCreateKeyA(rootKey, subkey.c_str(), &hKey);
    if (RegSetValueExA(hKey, entry.c_str(), 0, REG_SZ,
                       (const BYTE *) value.c_str(), value.length()) == ERROR_SUCCESS)
    {
        RegCloseKey(hKey);
        return true;
    }
    else
    {
        RegCloseKey(hKey);
        return false;
    }
}

bool WindowsRegistry::createEntry(HKEY rootKey, const std::string &subkey, const std::string &entry, DWORD value)
{
    HKEY hKey;

    RegCreateKeyA(rootKey, subkey.c_str(), &hKey);
    if (RegSetValueExA(hKey, entry.c_str(), 0, REG_DWORD,
                       reinterpret_cast <BYTE *> (&value),
                       sizeof(DWORD)) == ERROR_SUCCESS)
    {
        RegCloseKey(hKey);
        return true;
    }
    else
    {
        RegCloseKey(hKey);
        return false;
    }
}

bool WindowsRegistry::removeEntry(HKEY rootKey, const std::string & subkey, const std::string & entry)
{
    HKEY hKey;

    if (RegOpenKeyExA(rootKey, subkey.c_str(), 0, KEY_WRITE, &hKey) == ERROR_SUCCESS)
    {
        if (RegDeleteValueA(hKey, entry.c_str()) != ERROR_SUCCESS)
        {
            RegCloseKey(hKey);
            return false;
        }
        else
        {
            RegCloseKey(hKey);
            return true;
        }
    }

    return false;
}
